package com.yfqy.admin.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.github.promeg.pinyinhelper.Pinyin;
import com.google.common.collect.Lists;
import com.yfqy.admin.conf.Idgenerator.SnowflakeIdGenerator;
import com.yfqy.admin.constant.MyConstants;
import com.yfqy.admin.domain.dto.QueryById;
import com.yfqy.admin.domain.dto.system.AddMenusToRole;
import com.yfqy.admin.domain.dto.system.AddRole;
import com.yfqy.admin.domain.dto.system.AddRolesToUser;
import com.yfqy.admin.domain.dto.system.AddSysMenu;
import com.yfqy.admin.domain.dto.system.AddSysUser;
import com.yfqy.admin.domain.dto.system.MenusWithRole;
import com.yfqy.admin.domain.dto.system.ModifySysMenu;
import com.yfqy.admin.domain.dto.system.ModifySysRole;
import com.yfqy.admin.domain.dto.system.ModifySysUser;
import com.yfqy.admin.domain.dto.system.RolesWithUser;
import com.yfqy.admin.domain.dto.system.SysMenuDetail;
import com.yfqy.admin.domain.dto.system.SysMenuQuery;
import com.yfqy.admin.domain.dto.system.SysRoleDetail;
import com.yfqy.admin.domain.dto.system.SysRoleQuery;
import com.yfqy.admin.domain.dto.system.SysUserDetail;
import com.yfqy.admin.domain.dto.system.SysUserQuery;
import com.yfqy.admin.domain.entity.SysMenu;
import com.yfqy.admin.domain.entity.SysRole;
import com.yfqy.admin.domain.entity.SysUser;
import com.yfqy.admin.domain.mapper.SysMenuMapper;
import com.yfqy.admin.domain.mapper.SysRoleMapper;
import com.yfqy.admin.domain.mapper.SysRoleMenuMapper;
import com.yfqy.admin.domain.mapper.SysUserMapper;
import com.yfqy.admin.domain.mapper.SysUserRoleMapper;
import com.yfqy.admin.domain.vo.common.ResultVO;
import com.yfqy.admin.enums.MenuTypeEnum;
import com.yfqy.admin.enums.ResponseEnum;
import com.yfqy.admin.security.login.LoginUserInfo;
import com.yfqy.admin.service.RefreshAuthority;
import com.yfqy.admin.service.SystemManagerService;
import com.yfqy.admin.transform.UserNameTranslator;
import com.yfqy.admin.util.AuthUserContext;
import com.yfqy.admin.util.ExceptionTool;
import com.yfqy.admin.util.TreeBuilder;
import jakarta.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Service
public class SystemManagerServiceImpl implements SystemManagerService {

    private static final Logger LOGGER = LoggerFactory.getLogger(SystemManagerServiceImpl.class);

    @Resource
    private SysUserMapper sysUserMapper;
    @Resource
    private SysRoleMapper sysRoleMapper;
    @Resource
    private SysMenuMapper sysMenuMapper;
    @Resource
    private SysUserRoleMapper sysUserRoleMapper;
    @Resource
    private SysRoleMenuMapper sysRoleMenuMapper;
    @Resource(name = "BCryptPasswordEncoder")
    private PasswordEncoder passwordEncoder;
    @Resource
    private UserNameTranslator userNameTranslator;
    @Resource
    private SnowflakeIdGenerator idGenerator;
    @Resource(name = "defaultThreadPoolExecutor")
    private ThreadPoolExecutor threadPoolExecutor;
    @Resource
    private RefreshAuthority refreshAuthority;

    @Override
    public ResultVO<String> addSysUser(AddSysUser addSysUser) {
        SysUser sysUserByUsername = sysUserMapper.selectOneByUsername(addSysUser.getUsername());
        if (Objects.nonNull(sysUserByUsername)) {
            ExceptionTool.throwException(ResponseEnum.USERNAME_EXIST);
        }
        SysUser sysUserByEmail = sysUserMapper.selectOneByEmail(addSysUser.getEmail());
        if (Objects.nonNull(sysUserByEmail)) {
            ExceptionTool.throwException(ResponseEnum.EMAIL_EXIST);
        }
        SysUser bean = BeanUtil.toBean(addSysUser, SysUser.class);
        LoginUserInfo loginUserInfo = AuthUserContext.getLocalAuthUser();
        Long createdBy = Objects.nonNull(loginUserInfo) ? loginUserInfo.getId() : MyConstants._L1;
        bean.setCreatedBy(createdBy);
        bean.setModifiedBy(createdBy);
        bean.setId(idGenerator.nextId());
        bean.setPassword(passwordEncoder.encode(addSysUser.getPassword()));
        sysUserMapper.insertSelective(bean);
        return ResultVO.data(bean.getId().toString());
    }

    @Override
    public ResultVO<SysUserDetail> getSysUserById(Long id) {
        SysUser sysUser = sysUserMapper.selectByPrimaryKey(id);
        if (Objects.isNull(sysUser)) {
            return ResultVO.fail(ResponseEnum.USER_NOT_EXIST);
        }
        SysUserDetail userDetail = BeanUtil.toBean(sysUser, SysUserDetail.class);
        List<SysRoleDetail> roles = sysRoleMapper.selectUserRoles(sysUser.getId());
        if (CollUtil.isNotEmpty(roles)) {
            //
            List<SysMenuDetail> menus;
            if (roles.stream().anyMatch(r -> r.getIsAdmin() == MyConstants.BT1)) {
                menus = sysMenuMapper.selectAdminMenus();
            } else {
                List<Long> roleIds = roles.stream().map(SysRoleDetail::getId).toList();
                LOGGER.info("用户id={}，对应的角色ids={}", id, roleIds);
                menus = sysMenuMapper.selectRolesMenus(roleIds);
            }
            if (CollUtil.isNotEmpty(menus)) {
                TreeBuilder<SysMenuDetail, Long> builder = new TreeBuilder<>(
                        SysMenuDetail::getId, SysMenuDetail::getPid, SysMenuDetail::getChildren, SysMenuDetail::setChildren
                );
                List<SysMenuDetail> tree = builder.build(menus);
                // 用户的菜单tree
                userDetail.setMenus(tree);
            }
        }
        userNameTranslator.translationUser(userDetail);
        if (CollUtil.isNotEmpty(roles)) {
            userNameTranslator.translationUser(roles);
            userDetail.setRoleNames(roles);
        }
        return ResultVO.data(userDetail);
    }

    @Override
    public ResultVO<PageInfo<SysUserDetail>> getSysUserPage(SysUserQuery sysUserQuery) {
        PageHelper.startPage(sysUserQuery.getPageIndex(), sysUserQuery.getPageSize());
        String keyword = sysUserQuery.getKeyword();

        String email = null, username = null;
        if (StringUtils.isNotBlank(keyword)) {
            if (keyword.matches(MyConstants.EMAIL_REGEX)) {
                // keyword is email
                email = keyword;
            } else {
                // keyword is username
                username = keyword;
            }
        }
        List<SysUserDetail> sysUsers = sysUserMapper.selectUserPageByKeywordAndStatus(email, username, sysUserQuery.getStatus());
        if (CollUtil.isNotEmpty(sysUsers)) {
            userNameTranslator.translationUser(sysUsers);
        }
        PageInfo<SysUserDetail> pageInfo = new PageInfo<>(sysUsers);
        PageHelper.clearPage();
        return ResultVO.data(pageInfo);
    }

    @Override
    public ResultVO<Void> modifySysUser(ModifySysUser modifySysUser) {
        SysUser existingSysUser = sysUserMapper.selectByPrimaryKey(modifySysUser.getId());
        if (Objects.isNull(existingSysUser)) {
            return ResultVO.fail(ResponseEnum.USER_NOT_EXIST);
        }
        SysUser sysUserByEmail = sysUserMapper.selectOneByEmail(modifySysUser.getEmail());
        if (Objects.isNull(sysUserByEmail)) {
            existingSysUser.setEmail(modifySysUser.getEmail());
        } else if (!sysUserByEmail.getId().equals(existingSysUser.getId())) {
            return ResultVO.fail(ResponseEnum.EMAIL_EXIST);
        }
        if (StringUtils.isNotBlank(modifySysUser.getPassword())) {
            existingSysUser.setPassword(passwordEncoder.encode(modifySysUser.getPassword()));
        }
        if (StringUtils.isNotBlank(modifySysUser.getNickname())) {
            existingSysUser.setNickname(modifySysUser.getNickname());
        }
        LoginUserInfo loginUserInfo = AuthUserContext.getLocalAuthUser();
        if (Objects.nonNull(loginUserInfo)) {
            existingSysUser.setModifiedBy(loginUserInfo.getId());
        }
        // 如果是禁用强制用户退出登录
        boolean refreshUserAuthority = false;
        if (!Objects.equals(existingSysUser.getStatus(), modifySysUser.getStatus())
                && modifySysUser.getStatus() == MyConstants.BT2) {
            existingSysUser.setStatus(modifySysUser.getStatus());
            refreshUserAuthority = true;
        }
        sysUserMapper.updateByPrimaryKeySelective(existingSysUser);

        if (refreshUserAuthority) {
            TransactionSynchronizationManager.registerSynchronization(
                    new TransactionSynchronization() {
                        @Override
                        public void afterCommit() {
                            refreshAuthority.refreshAuthorityBySysUserId(existingSysUser.getId());
                        }
                    }
            );
        }
        return ResultVO.success();
    }

    @Override
    @Transactional
    public ResultVO<String> addRolesToUser(AddRolesToUser addRolesToUser) {
        // 1. 校验用户有效性
        SysUser sysUser = sysUserMapper.selectByPrimaryKey(addRolesToUser.getUserId());
        if (Objects.isNull(sysUser) || sysUser.getStatus() != MyConstants.BT1) {
            return ResultVO.fail(ResponseEnum.USER_IS_INVALID);
        }

        // 2. 获取操作人信息
        Long createdBy = Optional.ofNullable(AuthUserContext.getLocalAuthUser())
                .map(LoginUserInfo::getId)
                .orElse(MyConstants._L1);

        // 3. 处理角色变更
        handleRoleChanges(addRolesToUser, createdBy);

        // 4. 注册事务提交后的回调
        TransactionSynchronizationManager.registerSynchronization(
                new TransactionSynchronization() {
                    @Override
                    public void afterCommit() {
                        refreshUserAuthorityAsync(addRolesToUser.getUserId());
                    }
                }
        );

        return ResultVO.success();
    }

    private void handleRoleChanges(AddRolesToUser addRolesToUser, Long createdBy) {
        List<Long> newRoleIds = addRolesToUser.getRoleIds();

        if (CollUtil.isEmpty(newRoleIds)) {
            // 清空所有角色
            sysUserRoleMapper.deleteUserRolesWithModifyUser(addRolesToUser.getUserId(), createdBy);
            return;
        }

        // 校验角色有效性
        List<SysRole> validRoles = sysRoleMapper.selectByIds(newRoleIds);
        if (validRoles.size() != newRoleIds.size()) {
            throw new IllegalArgumentException("角色参数校验异常，请重新选择");
        }

        List<Long> currentRoleIds = sysUserRoleMapper.selectUserRoleIds(addRolesToUser.getUserId());

        if (CollUtil.isEmpty(currentRoleIds)) {
            // 直接添加所有新角色
            sysUserRoleMapper.addRolesToUser(addRolesToUser.getUserId(), newRoleIds, createdBy);
            return;
        }

        // 计算需要删除和添加的角色
        Set<Long> newRoleSet = new HashSet<>(newRoleIds);
        Set<Long> currentRoleSet = new HashSet<>(currentRoleIds);

        List<Long> rolesToRemove = currentRoleSet.stream()
                .filter(id -> !newRoleSet.contains(id))
                .collect(Collectors.toList());

        List<Long> rolesToAdd = newRoleSet.stream()
                .filter(id -> !currentRoleSet.contains(id))
                .collect(Collectors.toList());

        // 执行变更
        if (CollUtil.isNotEmpty(rolesToRemove)) {
            sysUserRoleMapper.deletePartUserRolesWithModifyUser(addRolesToUser.getUserId(), createdBy, rolesToRemove);
        }

        if (CollUtil.isNotEmpty(rolesToAdd)) {
            sysUserRoleMapper.addRolesToUser(addRolesToUser.getUserId(), rolesToAdd, createdBy);
        }
    }

    @Override
    public ResultVO<String> addSysRole(AddRole addRole) {
        // 1. 校验角色名是否已存在
        if (sysRoleMapper.selectOneByRoleName(addRole.getRoleName()) != null) {
            throw new IllegalArgumentException("角色名称已存在，不可重复添加");
        }

        // 2. 构建角色实体
        SysRole newRole = buildSysRole(addRole);

        // 3. 处理角色编码
        handleRoleCode(addRole, newRole);

        // 4. 保存角色
        sysRoleMapper.insertSelective(newRole);

        return ResultVO.data(newRole.getId().toString());
    }

    private SysRole buildSysRole(AddRole addRole) {
        SysRole role = BeanUtil.toBean(addRole, SysRole.class);
        LoginUserInfo currentUser = AuthUserContext.getLocalAuthUser();
        if (currentUser != null) {
            role.setCreatedBy(currentUser.getId());
            role.setModifiedBy(currentUser.getId());
        }
        role.setId(idGenerator.nextId());
        return role;
    }

    private void handleRoleCode(AddRole addRole, SysRole role) {
        // 如果明确提供了角色编码
        if (StringUtils.isNotBlank(addRole.getRoleCode())) {
            if (sysRoleMapper.selectOneByRoleCode(addRole.getRoleCode()) != null) {
                throw new IllegalArgumentException("角色code已存在，不可重复添加");
            }
            role.setRoleCode(addRole.getRoleCode());
        }
        // 自动生成拼音编码
        else {
            try {
                role.setRoleCode(Pinyin.toPinyin(addRole.getRoleName(), ""));
            } catch (Exception e) {
                LOGGER.warn("角色名转拼音失败，角色名: {}", addRole.getRoleName(), e);
                role.setRoleCode("ROLE_" + role.getId()); // 兜底方案
            }
        }
    }

    @Override
    public ResultVO<SysRoleDetail> getSysRoleById(Long id) {
        SysRole sysRole = sysRoleMapper.selectByPrimaryKey(id);
        if (Objects.isNull(sysRole)) {
            return ResultVO.fail(ResponseEnum.ROLE_NOT_EXIST);
        }
        SysRoleDetail roleDetail = BeanUtil.toBean(sysRole, SysRoleDetail.class);
        List<SysMenuDetail> sysMenuDetails;
        if (roleDetail.getIsAdmin() == MyConstants.BT1) {
            sysMenuDetails = sysMenuMapper.selectAdminMenus();
        } else {
            sysMenuDetails = sysMenuMapper.selectRolesMenus(Lists.newArrayList(roleDetail.getId()));
        }
        TreeBuilder<SysMenuDetail, Long> builder = new TreeBuilder<>(
                SysMenuDetail::getId, SysMenuDetail::getPid, SysMenuDetail::getChildren, SysMenuDetail::setChildren
        );
        List<SysMenuDetail> tree = builder.build(sysMenuDetails);
        roleDetail.setMenus(tree);
        userNameTranslator.translationUser(roleDetail);
        return ResultVO.data(roleDetail);
    }

    @Override
    public ResultVO<PageInfo<SysRoleDetail>> getSysRolePage(SysRoleQuery sysRoleQuery) {
        PageHelper.startPage(sysRoleQuery.getPageIndex(), sysRoleQuery.getPageSize());
        List<SysRoleDetail> roleDetails = sysRoleMapper.selectPageByRoleNameAndStatus(sysRoleQuery.getRoleName(), sysRoleQuery.getStatus());
        if (CollUtil.isNotEmpty(roleDetails)) {
            List<Long> userIds = roleDetails.stream().flatMap(u -> Stream.of(u.getCreatedBy(), u.getModifiedBy()))
                    .filter(id -> !MyConstants._L1.equals(id)).toList();
            if (CollUtil.isNotEmpty(userIds)) {
                userNameTranslator.translationUser(roleDetails);
            }
        }
        PageInfo<SysRoleDetail> pageInfo = new PageInfo<>(roleDetails);
        PageHelper.clearPage();
        return ResultVO.data(pageInfo);
    }

    @Override
    public ResultVO<String> modifySysRole(ModifySysRole modifySysRole) {
        // 1. 校验角色是否存在
        SysRole existingRole = sysRoleMapper.selectByPrimaryKey(modifySysRole.getId());
        if (existingRole == null) {
            return ResultVO.fail(ResponseEnum.ROLE_NOT_EXIST);
        }
        // 2. 校验角色名是否冲突
        if (isRoleNameConflict(modifySysRole, existingRole)) {
            return ResultVO.fail(ResponseEnum.ROLE_EXIST);
        }
        // 3. 更新角色信息
        updateRoleInfo(modifySysRole, existingRole);
        LoginUserInfo loginUserInfo = AuthUserContext.getLocalAuthUser();
        Long modifiedBy = Objects.nonNull(loginUserInfo) ? loginUserInfo.getId() : MyConstants._L1;
        existingRole.setModifiedBy(modifiedBy);
        sysRoleMapper.updateByPrimaryKeySelective(existingRole);
        return ResultVO.success();
    }

    private void updateRoleInfo(ModifySysRole modifySysRole, SysRole role) {
        if (!StringUtils.equals(modifySysRole.getRoleName(), role.getRoleName())) {
            role.setRoleName(modifySysRole.getRoleName());
            try {
                role.setRoleCode(Pinyin.toPinyin(modifySysRole.getRoleName(), ""));
            } catch (Exception e) {
                LOGGER.warn("角色名转拼音失败，角色名: {}", modifySysRole.getRoleName(), e);
                role.setRoleCode("ROLE_" + role.getId()); // 兜底方案
            }
        }
    }

    private boolean isRoleNameConflict(ModifySysRole modifySysRole, SysRole existingRole) {
        if (!StringUtils.equals(modifySysRole.getRoleName(), existingRole.getRoleName())) {
            SysRole sameNameRole = sysRoleMapper.selectOneByRoleName(modifySysRole.getRoleName());
            return sameNameRole != null && !sameNameRole.getId().equals(existingRole.getId());
        }
        return false;
    }

    @Override
    public ResultVO<Long> addSysMenu(AddSysMenu addSysMenu) {
        if (Objects.equals(MenuTypeEnum.menu.getMenuType(), addSysMenu.getMenuType())) {
            if (StringUtils.isBlank(addSysMenu.getUrl())) {
                return ResultVO.fail(ResponseEnum.MENU_URL_ISNULL);
            }
        }
        if (!Objects.equals(MenuTypeEnum.directory.getMenuType(), addSysMenu.getMenuType())) {
            if (StringUtils.isBlank(addSysMenu.getCode())) {
                return ResultVO.fail(ResponseEnum.MENU_CODE_ISNULL);
            }
        }
        if (StringUtils.isNotBlank(addSysMenu.getCode())) {
            SysMenu sysMenuByCode = sysMenuMapper.selectOneMenusByCode(addSysMenu.getCode());
            if (Objects.nonNull(sysMenuByCode)) {
                return ResultVO.fail(ResponseEnum.MENU_CODE_IS_EXIST);
            }
        }
        // 新增菜单的Id
        Long newMenuId = idGenerator.nextId();
        SysMenu bean = BeanUtil.toBean(addSysMenu, SysMenu.class);
        if (!Objects.equals(addSysMenu.getPid(), MyConstants.L0)) {
            SysMenu parentMenu = sysMenuMapper.selectByPrimaryKey(addSysMenu.getPid());
            if (Objects.isNull(parentMenu) || parentMenu.getStatus() != MyConstants.BT1) {
                return ResultVO.fail("父菜单不存在或无效");
            }
            bean.setPath(parentMenu.getPath() + "/" + newMenuId);
        } else {
            bean.setPath(String.valueOf(newMenuId));
        }
        LoginUserInfo loginUserInfo = AuthUserContext.getLocalAuthUser();
        if (Objects.nonNull(loginUserInfo)) {
            bean.setCreatedBy(loginUserInfo.getId());
            bean.setModifiedBy(loginUserInfo.getId());
        }
        bean.setId(newMenuId);
        sysMenuMapper.insertSelective(bean);
        return ResultVO.data(bean.getId());
    }

    @Override
    public ResultVO<SysMenuDetail> getSysMenuById(Long id) {
        SysMenuDetail menuDetail = sysMenuMapper.selectById(id);
        if (Objects.isNull(menuDetail)) {
            return ResultVO.fail(ResponseEnum.MENU_NOT_EXIST);
        }
        StringBuilder pathName = new StringBuilder();
        List<Long> menuPathIds = Arrays.stream(menuDetail.getPath().split("/")).map(Long::parseLong).toList();
        List<SysMenu> sysMenus = sysMenuMapper.selectByIds(menuPathIds);
        if (CollUtil.isNotEmpty(sysMenus)) {
            Map<Long, String> namuIdNameMap = sysMenus.stream().collect(Collectors.toMap(SysMenu::getId, SysMenu::getMenuName));
            menuPathIds.forEach(pathId -> {
                pathName.append("/").append(namuIdNameMap.get(pathId));
            });
        }
        menuDetail.setPath(pathName.toString());
        userNameTranslator.translationUser(menuDetail);
        return ResultVO.data(menuDetail);
    }

    @Override
    public ResultVO<List<SysMenuDetail>> getSysMenuTree() {
        List<SysMenuDetail> sysMenuDetails = sysMenuMapper.selectAdminMenus();
        TreeBuilder<SysMenuDetail, Long> builder = new TreeBuilder<>(
                SysMenuDetail::getId, SysMenuDetail::getPid, SysMenuDetail::getChildren, SysMenuDetail::setChildren
        );
        return ResultVO.data(builder.build(sysMenuDetails));
    }

    @Override
    public ResultVO<Void> modifySysMenu(ModifySysMenu modifySysMenu) {
        SysMenu existingSysMenu = sysMenuMapper.selectByPrimaryKey(modifySysMenu.getId());
        if (Objects.isNull(existingSysMenu)) {
            return ResultVO.fail(ResponseEnum.MENU_NOT_EXIST);
        }
        if (Objects.equals(MenuTypeEnum.menu.getMenuType(), modifySysMenu.getMenuType())) {
            if (StringUtils.isBlank(modifySysMenu.getUrl())) {
                return ResultVO.fail(ResponseEnum.MENU_URL_ISNULL);
            }
        }
        if (!Objects.equals(MenuTypeEnum.directory.getMenuType(), modifySysMenu.getMenuType())) {
            if (StringUtils.isBlank(modifySysMenu.getCode())) {
                return ResultVO.fail(ResponseEnum.MENU_CODE_ISNULL);
            }
        }
        if (!existingSysMenu.getPid().equals(modifySysMenu.getPid())) {
            if (!MyConstants.L0.equals(modifySysMenu.getPid())) {
                SysMenu parentMenu = sysMenuMapper.selectByPrimaryKey(modifySysMenu.getPid());
                if (Objects.isNull(parentMenu) || parentMenu.getStatus() != MyConstants.BT1) {
                    return ResultVO.fail("父菜单不存在或无效");
                }
                existingSysMenu.setPath(parentMenu.getPath() + "/" + existingSysMenu.getId());
            } else {
                existingSysMenu.setPath(String.valueOf(existingSysMenu.getId()));
            }
        }
        boolean refreshUserAuthority = false;
        if (!existingSysMenu.getCode().equals(modifySysMenu.getCode())) {
            SysMenu sysMenuByCode = sysMenuMapper.selectOneMenusByCode(modifySysMenu.getCode());
            if (Objects.nonNull(sysMenuByCode) && !sysMenuByCode.getId().equals(existingSysMenu.getId())) {
                return ResultVO.fail(ResponseEnum.MENU_CODE_IS_EXIST);
            }
            refreshUserAuthority = true;
        }
        LoginUserInfo loginUserInfo = AuthUserContext.getLocalAuthUser();
        Long modifiedBy = Objects.nonNull(loginUserInfo) ? loginUserInfo.getId() : MyConstants._L1;
        existingSysMenu.setModifiedBy(modifiedBy);
        // CopyOptions.create().setIgnoreNullValue(true)：忽略source中的空值
        BeanUtil.copyProperties(modifySysMenu, existingSysMenu, CopyOptions.create().setIgnoreNullValue(true));
        sysMenuMapper.updateByPrimaryKeySelective(existingSysMenu);

        // 修改了权限编码后，需要异步修改用户的权限
        if (refreshUserAuthority) {
            TransactionSynchronizationManager.registerSynchronization(
                    new TransactionSynchronization() {
                        @Override
                        public void afterCommit() {
                            List<Long> roleIds = sysRoleMenuMapper.selectRoleIdsByMenuId(existingSysMenu.getId());
                            if (CollUtil.isNotEmpty(roleIds)) {
                                List<Long> userIds = sysUserRoleMapper.selectUserIdsByRoleIds(roleIds);
                                if (CollUtil.isNotEmpty(userIds)) {
                                    userIds.forEach(userId -> {
                                        refreshAuthority.refreshAuthorityBySysUserId(userId);
                                    });
                                }
                            }
                        }
                    }
            );

        }
        return ResultVO.success();
    }

    @Override
    public ResultVO<PageInfo<SysMenuDetail>> getSysMenuPage(SysMenuQuery sysMenuQuery) {
        PageHelper.startPage(sysMenuQuery.getPageIndex(), sysMenuQuery.getPageSize());
        List<SysMenuDetail> sysMenuDetails = sysMenuMapper.getSysMenuPage(sysMenuQuery.getMenuName());
        PageInfo<SysMenuDetail> pageInfo = new PageInfo<>(sysMenuDetails);
        PageHelper.clearPage();
        return ResultVO.data(pageInfo);
    }

    @Override
    public ResultVO<List<SysMenuDetail>> getSysUserMenuTree() {
        LoginUserInfo loginUserInfo = AuthUserContext.getLocalAuthUser();
        if (Objects.isNull(loginUserInfo)) {
            LOGGER.warn("用户未登录，获取登录用的菜单权限失败");
            return ResultVO.data(Lists.newArrayList());
        }
        List<SysRoleDetail> roleDetails = sysRoleMapper.selectUserRoles(loginUserInfo.getId());
        List<SysMenuDetail> sysMenuDetails = null;
        if (roleDetails.stream().anyMatch(r -> r.getIsAdmin() == MyConstants.BT1)) {
            sysMenuDetails = sysMenuMapper.selectAdminMenus();
        } else {
            List<Long> roleIds = roleDetails.stream().map(SysRoleDetail::getId).toList();
            sysMenuDetails = sysMenuMapper.selectRolesMenus(roleIds);
        }
        sysMenuDetails = sysMenuDetails.stream().filter(md -> !MyConstants.DISPLAY_MENU_ROUT.contains(md.getUrl())).toList();
        TreeBuilder<SysMenuDetail, Long> builder = new TreeBuilder<>(
                SysMenuDetail::getId, SysMenuDetail::getPid, SysMenuDetail::getChildren, SysMenuDetail::setChildren
        );
        return ResultVO.data(builder.build(sysMenuDetails));
    }

    @Override
    @Transactional
    public ResultVO<String> addMenusToRole(AddMenusToRole addMenusToRole) {
        SysRole sysRole = sysRoleMapper.selectByPrimaryKey(addMenusToRole.getRoleId());
        if (Objects.isNull(sysRole) || sysRole.getStatus() != MyConstants.BT1) {
            return ResultVO.fail(ResponseEnum.ROLE_NOTEXIST_INVALID);
        }
        LoginUserInfo loginUserInfo = AuthUserContext.getLocalAuthUser();
        Long modifiedBy = Objects.nonNull(loginUserInfo) ? loginUserInfo.getId() : MyConstants._L1;
        // menuIds为空，直接删除角色的全部权限
        List<Long> addMenuIds = addMenusToRole.getMenuIds().stream()
                .filter(mid -> !MyConstants.L0.equals(mid)).collect(Collectors.toList());
        if (CollUtil.isEmpty(addMenuIds)) {
            sysRoleMenuMapper.deleteRoleMenusWithModifyUser(addMenusToRole.getRoleId(), modifiedBy);
        } else {
            List<SysMenu> sysMenus = sysMenuMapper.selectByIds(addMenuIds);
            List<Long> menuIdsValid = sysMenus.stream().map(SysMenu::getId).toList();
            if (!new HashSet<>(menuIdsValid).equals(new HashSet<>(addMenuIds))) {
                return ResultVO.fail("菜单参数校验异常，请重新选择");
            }
            // 角色现已绑定的权限
            List<Long> roleMenuIds = sysRoleMenuMapper.selectMenuIdsByRoleId(addMenusToRole.getRoleId());
            List<Long> intersection = (List<Long>) CollUtil.intersection(roleMenuIds, addMenuIds);
            roleMenuIds.removeAll(intersection);
            addMenuIds.removeAll(intersection);
            if (CollUtil.isNotEmpty(roleMenuIds)) {
                // 删除本次没有选择的权限
                sysRoleMenuMapper.deletePartRoleMenusWithModifyUser(roleMenuIds, addMenusToRole.getRoleId(), modifiedBy);
            }
            if (CollUtil.isNotEmpty(addMenuIds)) {
                // 绑定本次选择的剩余其他权限
                sysRoleMenuMapper.addMenusToRole(addMenuIds, addMenusToRole.getRoleId(), modifiedBy);
            }
        }
        // 添加角色后的权限后,异步刷新用户的权限
        List<Long> sysUserIds = sysUserRoleMapper.selectUserIdsByRoleId(addMenusToRole.getRoleId());
        // 4. 注册事务提交后的回调, 异步刷新账号权限
        TransactionSynchronizationManager.registerSynchronization(
                new TransactionSynchronization() {
                    @Override
                    public void afterCommit() {
                        if (CollUtil.isNotEmpty(sysUserIds)) {
                            LOGGER.info("角色绑定权限变更时异步刷新用户的权限，受影响的用户Id={}", sysUserIds);
                            sysUserIds.forEach(userId -> {
                                refreshAuthority.refreshAuthorityBySysUserId(userId);
                            });
                        }
                    }
                }
        );
        return ResultVO.success();
    }

    @Override
    public ResultVO<List<RolesWithUser>> rolesWithUser(QueryById queryById) {
        SysUser sysUser = sysUserMapper.selectByPrimaryKey(queryById.getId());
        if (Objects.isNull(sysUser) || sysUser.getStatus() != MyConstants.BT1) {
            ExceptionTool.throwException(ResponseEnum.USER_IS_INVALID);
        }
        // 系统中有效的角色列表
        List<RolesWithUser> roleWithUserList = sysRoleMapper.selectAllValid();
        // 用户已绑定的角色id集合
        List<Long> roleIds = sysUserRoleMapper.selectUserRoleIds(queryById.getId());
        roleWithUserList.forEach(roleWithUser -> {
            if (roleIds.contains(roleWithUser.getId())) {
                roleWithUser.setSelected(true);
            }
        });
        return ResultVO.data(roleWithUserList);
    }

    @Override
    public ResultVO<List<MenusWithRole>> menusWithRole(QueryById queryById) {
        SysRole sysRole = sysRoleMapper.selectByPrimaryKey(queryById.getId());
        if (Objects.isNull(sysRole) || sysRole.getStatus() != MyConstants.BT1) {
            return ResultVO.fail(ResponseEnum.ROLE_NOTEXIST_INVALID);
        }
        if (sysRole.getIsAdmin() == MyConstants.BT1) {
            return ResultVO.success("超管角色不需要绑定菜单权限");
        }
        // 系统中有效的菜单列表
        List<MenusWithRole> menusWithRole = sysMenuMapper.selectAllValid();
        // 角色已绑定的菜单id集合
        List<Long> roleMenuIds = sysRoleMenuMapper.selectMenuIdsByRoleId(queryById.getId());
        menusWithRole.forEach(menu -> {
            if (roleMenuIds.contains(menu.getId())) {
                menu.setSelected(true);
            }
        });
        TreeBuilder<MenusWithRole, Long> builder = new TreeBuilder<>(
                MenusWithRole::getId, MenusWithRole::getPid, MenusWithRole::getChildren, MenusWithRole::setChildren
        );
        List<MenusWithRole> tree4MenusWithRole = builder.build(menusWithRole);
        return ResultVO.data(tree4MenusWithRole);
    }

    @Override
    @Transactional
    public ResultVO<Void> deleteSysMenu(Long id) {
        SysMenu sysMenu = sysMenuMapper.selectByPrimaryKey(id);
        if (Objects.isNull(sysMenu) || sysMenu.getStatus() != MyConstants.BT1) {
            return ResultVO.fail(ResponseEnum.ROLE_NOTEXIST_INVALID);
        }
        List<SysMenu> childMenus = sysMenuMapper.selectByPid(id);
        if (CollUtil.isNotEmpty(childMenus)) {
            return ResultVO.fail(ResponseEnum.MENU_CANNOT_DELETE);
        }
        sysMenu.setStatus((byte) 0);
        LoginUserInfo loginUserInfo = AuthUserContext.getLocalAuthUser();
        Long modifiedBy = Objects.nonNull(loginUserInfo) ? loginUserInfo.getId() : MyConstants._L1;
        sysMenu.setModifiedBy(modifiedBy);

        // 删除权限前查询出可能会影响的用户集合
        List<Long> userIds = null;
        List<Long> roleIds = sysRoleMenuMapper.selectRoleIdsByMenuId(id);
        if (CollUtil.isNotEmpty(roleIds)) {
            userIds = sysUserRoleMapper.selectUserIdsByRoleIds(roleIds);
        }

        // 逻辑删除菜单
        sysMenuMapper.updateByPrimaryKeySelective(sysMenu);
        // 删除角色菜单关系
        sysRoleMenuMapper.deleteRoleMenusByMenuId(sysMenu.getId(), modifiedBy);

        List<Long> finalUserIds = userIds;
        TransactionSynchronizationManager.registerSynchronization(
                new TransactionSynchronization() {
                    @Override
                    public void afterCommit() {
                        if (CollUtil.isNotEmpty(finalUserIds)) {
                            finalUserIds.forEach(userId -> {
                                refreshAuthority.refreshAuthorityBySysUserId(userId);
                            });
                        }
                    }
                }
        );
        return ResultVO.success();
    }

    @Override
    @Transactional
    public ResultVO<String> deleteSysRole(Long roleId) {
        SysRole sysRole = sysRoleMapper.selectByPrimaryKey(roleId);
        if (Objects.isNull(sysRole) || sysRole.getStatus() != MyConstants.BT1) {
            return ResultVO.fail(ResponseEnum.ROLE_NOTEXIST_INVALID);
        }
        if (sysRole.getIsAdmin() == MyConstants.BT1) {
            return ResultVO.fail(ResponseEnum.ROLE_CANNOT_DELETE);
        }
        sysRole.setStatus((byte) 0);
        LoginUserInfo loginUserInfo = AuthUserContext.getLocalAuthUser();
        Long modifiedBy = Objects.nonNull(loginUserInfo) ? loginUserInfo.getId() : MyConstants._L1;
        sysRole.setModifiedBy(modifiedBy);
        // 开始删除前查询出该角色会影响的用户
        List<Long> sysUserIds = sysUserRoleMapper.selectUserIdsByRoleId(roleId);
        // 逻辑删除角色
        sysRoleMapper.updateByPrimaryKeySelective(sysRole);
        // 逻辑删除用户角色关系
        sysUserRoleMapper.updateUserRolesByRoleId(roleId, (byte) 0, modifiedBy);
        // 逻辑删除角色权限关系
        sysRoleMenuMapper.deleteRoleMenusByRoleId(roleId, modifiedBy);

        // 4. 注册事务提交后的回调, 异步刷新账号权限
        TransactionSynchronizationManager.registerSynchronization(
                new TransactionSynchronization() {
                    @Override
                    public void afterCommit() {
                        if (CollUtil.isNotEmpty(sysUserIds)) {
                            LOGGER.info("删除角色后异步刷新用户的权限，受影响的用户Id={}", sysUserIds);
                            sysUserIds.forEach(userId -> {
                                refreshAuthority.refreshAuthorityBySysUserId(userId);
                            });
                        }
                    }
                }
        );

        return ResultVO.success();
    }

    @Override
    public ResultVO<String> deleteSysUser(Long userId) {
        if (MyConstants.L1.equals(userId)) {
            LOGGER.warn("系统特殊账号不可删除");
            return ResultVO.fail(ResponseEnum.USER_IS_INVALID);
        }
        SysUser sysUser = sysUserMapper.selectByPrimaryKey(userId);
        if (Objects.isNull(sysUser) || sysUser.getStatus() == MyConstants.BT3) {
            return ResultVO.fail("用户不存或已删除");
        }
        LoginUserInfo loginUserInfo = AuthUserContext.getLocalAuthUser();
        Long modifiedBy = Objects.nonNull(loginUserInfo) ? loginUserInfo.getId() : MyConstants._L1;
        sysUser.setStatus(MyConstants.BT3);
        sysUser.setModifiedBy(modifiedBy);
        // 逻辑删除用户
        sysUserMapper.updateByPrimaryKeySelective(sysUser);
        // 逻辑删除用户角色关联关系
        sysUserRoleMapper.deleteUserRolesWithModifyUser(userId, modifiedBy);

        TransactionSynchronizationManager.registerSynchronization(
                new TransactionSynchronization() {
                    @Override
                    public void afterCommit() {
                        threadPoolExecutor.execute(() -> {
                            LOGGER.info("删除用户后异步调用刷新用户权限userId={}", userId);
                            refreshAuthority.refreshAuthorityBySysUserId(userId);
                        });
                    }
                }
        );

        return ResultVO.success();
    }


    private void refreshUserAuthorityAsync(Long userId) {
        threadPoolExecutor.execute(() -> {
            try {
                refreshAuthority.refreshAuthorityBySysUserId(userId);
            } catch (Exception e) {
                LOGGER.error("刷新用户权限失败，用户ID: {}", userId, e);
            }
        });
    }
}
